package com.zyl.file.service.impl;


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zyl.file.constant.FileConstants;
import com.zyl.file.constant.StateConstants;
import com.zyl.file.exception.MyException;
import com.zyl.file.mapper.StEquipmentMapper;
import com.zyl.file.mapper.StFileMapper;
import com.zyl.file.platform.FileStorage;
import com.zyl.file.platform.FileStorageService;
import com.zyl.file.po.StEquipment;
import com.zyl.file.po.StFile;
import com.zyl.file.result.ResultCode;
import com.zyl.file.service.CacheCommonService;
import com.zyl.file.service.FileDealService;
import com.zyl.file.util.FileEncryptUtils;
import com.zyl.file.util.FileUtils;
import com.zyl.file.util.ZipUtils;
import com.zyl.file.vo.DownFileVO;
import com.zyl.file.vo.WaterMarkConfigVO;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * 文件处理实现类
 *
 * @author： zyl
 * @Description：
 * @since 2023/7/6 17:58
 */
@Slf4j
@Service
public class FileDealServiceImpl implements FileDealService {

    public final static List<String> CANSPLITFILETYPE = Arrays.asList("pdf", "ofd", "tiff", "tif", "heif", "txt", "ppt", "pptx", "xls", "xlsx", "docx", "doc", "wps");
    public final static List<String> VIDEOS = Arrays.asList("wmv", "asf", "rm", "rmvb", "avi", "mov", "mpg", "flv", "mp4");
    public final static List<String> AUDIOS = Arrays.asList("amr", "ogg", "m4a", "mp3");
    public final static List<String> DOCS = Arrays.asList("txt", "doc", "wps", "docx", "xls", "ppt", "pptx", "xlsx", "ini", "pdf");

    private final static String SPLIT = "-";
    private final static String RANGE = "range";
    @Resource
    private StFileMapper stFileMapper;
    @Resource
    private StEquipmentMapper stEquipmentMapper;
//    @Resource
//    private RedisUtils redisUtil;

    @Resource
    private FileStorageService fileStorageService;

    @Resource
    private CacheCommonService cacheCommonService;

    @Value("${upload.file_down_temp:/home/down/}")
    private String fileDownTemp;

    @Qualifier("downTaskExecutor")
    private Executor executor;

    @Override
    public void createInputStreamResourcesCache(HttpServletRequest request, HttpServletResponse response, Long fileId) {
        StFile stFile = stFileMapper.selectById(fileId);
        InputStream inputStream = getInputStream(fileId, stFile);
        try (ServletOutputStream servletOutputStream = response.getOutputStream()) {
            String ext = stFile.getExt().toLowerCase();
            if (inputStream == null || inputStream.available() == 0) {
                throw new MyException(ResultCode.PARAM_ERROR, "文件不存在");
            } else {
                if (VIDEOS.contains(ext) || AUDIOS.contains(ext)) {
                    loadVideosAudisoPaf(request, response, stFile, inputStream, ext);
                } else if (DOCS.contains(ext)) {
                    //获取pdf文件路径
                    String filePath = stFile.getUrl();;
                    //懒加载pdf
                    loadPdf(response, request, filePath);
                } else {
                    // 将输入流转换为字节数组
                    response.setHeader("Content-disposition", "inline;filename=" + stFile.getOriginalFilename());
                    response.setContentType("application/octet-stream");
                    response.setHeader("Cache-Control", "no-store");
                    response.setHeader("Pragma", "no-cache");
                    response.setHeader("Expires", "0");
                    response.setHeader("Accept-Ranges", "bytes");
                    byte[] bytes = new byte[1024];
                    while (inputStream.read(bytes) != -1) {
                        servletOutputStream.write(bytes);
                        servletOutputStream.flush();
                    }
                }
            }
        } catch (IOException e) {
            log.error("异常描述", e);
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            try {
                if (null != inputStream) {
                    inputStream.close();
                    inputStream = null;
                }
            } catch (IOException e) {
                log.error("关闭文件流失败", e);
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    public InputStream getInputStream(Long fileId, StFile stFile) {
        StopWatch sw = new StopWatch();
        //文件后缀
        String fileExt = stFile.getExt().toLowerCase();
        //文件流
        InputStream inputStream = null;
        log.info("文件类型: {}", fileExt);
        String fileName = String.valueOf(fileId);

        //没开启水印 或者 开启水印但是没获取到包含水印的文件流  就去缓存拿没水印的文件流
        if (inputStream == null) {
            log.info("从缓存中获取文件");
            // 从缓存中获取文件
            inputStream = cacheCommonService.getFileCache(fileName, fileExt);
        }
        try {
            if (inputStream == null || inputStream.available() == 0) {
                //直接从存储设备中获取
                sw.start("存储设备获取文件耗时");
                //获取对应的存储平台
                FileStorage fileStorage = fileStorageService.getFileStorage(String.valueOf(stFile.getEquipmentId()));
                //从存储设备中获取文件流
                inputStream = fileStorage.getFileStream(stFile.getObjectKey());
                if (inputStream == null || inputStream.available() == 0) {
                    log.info("存储设备中找不到文件");
                    throw new MyException(ResultCode.PARAM_ERROR, "文件不存在");
                }
                //解密
                if (FileConstants.IS_ENCRYPT.equals(stFile.getIsEncrypt())) {
                    inputStream = FileEncryptUtils.decrypt(inputStream, stFile.getEncryptKey(), stFile.getEncryptIndex());
                }
                if (inputStream.available() == 0) {
                    log.info("解密失败");
                    throw new MyException(ResultCode.PARAM_ERROR, "解密失败");
                }
                //重新将文件缓存到缓存目录
                log.info("重新将文件缓存到缓存目录");
//                cacheCommonService.cacheFile(inputStream, stFile.getUrl(), fileId, fileExt,0, stFile.getEncryptKey(), stFile.getEncryptIndex());
                sw.stop();
            }
        } catch (IOException e) {
            log.error("读取文件流出错");
            throw new RuntimeException(e.getMessage(), e);
        }
        log.info(sw.prettyPrint());
        return inputStream;
    }

    @Override
    public void downFile(String sessionId, DownFileVO downFileVO, HttpServletResponse response) {
        Assert.notNull(downFileVO.getFileId(), "文件id不能为空!");
        if (downFileVO.getIsPack().equals(StateConstants.COMMON_ONE)) {
            //将文件封装到压缩包中
            //生成的压缩文件临时路径
            String zipPath = fileDownTemp + System.currentTimeMillis() + ".zip";
            InputStream fileZipInputStream = getFileZipInputStream(downFileVO.getFileId(), zipPath);
            String fileName = UUID.fastUUID() + ".zip";
            response.setContentType("application/octet-stream");
            response.setContentLengthLong(new File(zipPath).length());
            response.setHeader("Content-disposition", "attachment;filename=" + fileName);
            response.setHeader("Cache-Control", "no-store");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Expires", "0");
            try (ServletOutputStream outputStream = response.getOutputStream();
                 BufferedInputStream bin = new BufferedInputStream(fileZipInputStream)) {
                byte[] b = new byte[1024 * 4];
                int len = 0;
                while ((len = bin.read(b)) != -1) {
                    outputStream.write(b, 0, len);
                }
                outputStream.flush();
                log.info("文件的二进制流输出完成,下载文件名:{}", fileName);
                //删除生成的压缩文件临时路径
                FileUtil.del(zipPath);
            } catch (IOException e) {
                log.error("异常描述", e);
                throw new RuntimeException(e.getMessage(), e);
            } finally {
                try {
                    if (null != fileZipInputStream) {
                        fileZipInputStream.close();
                    }
                } catch (IOException e) {
                    log.error("异常描述", e);
                    throw new RuntimeException(e.getMessage(), e);
                }

            }
        } else {
            //单个文件形式下载
            Assert.isTrue(CollectionUtils.isEmpty(downFileVO.getFileId()) || downFileVO.getFileId().size() != StateConstants.COMMON_ONE, "传参有误");
            StFile stFile = stFileMapper.selectOne(new QueryWrapper<StFile>().eq("id", downFileVO.getFileId().get(StateConstants.ZERO)));
            Assert.notNull(stFile, "参数错误");
            InputStream in = null;
            BufferedInputStream bin = null;
            ServletOutputStream outStream = null;
            // 获取文件输入流
            long l1 = System.currentTimeMillis();
            in = getDownInputStream(stFile);
            long l2 = System.currentTimeMillis();
            log.info("获取文件输入流时间：{}", l2 - l1);
            String originalFilename = getOriginalFilename(downFileVO, stFile);
            // 设置响应头，指定文件类型和下载的文件名
            // 根据文件扩展名获取对应的 MIME 类型
            response.setContentType("application/octet-stream");
            response.setHeader("Cache-Control", "no-store");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Expires", "0");
            String encode = null;
            try {
                encode = URLEncoder.encode(originalFilename, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                log.error("异常描述", e);
                throw new RuntimeException(e.getMessage(), e);
            }
            response.setHeader("Content-disposition", "attachment;filename=" + encode);
            try {
                bin = new BufferedInputStream(in);
                outStream = response.getOutputStream();
                byte[] b = new byte[1024 * 4];
                int len = 0;
                while ((len = bin.read(b)) != -1) {
                    outStream.write(b, 0, len);
                }
                log.info("文件的二进制流输出完成,下载文件名:{}", originalFilename);
            } catch (IOException e) {
                log.error("下载失败", e);
                throw new RuntimeException(e.getMessage(), e);
            } finally {
                try {
                    log.info("正在关闭文件流");
                    if (null != outStream) {
                        outStream.flush();
                        outStream.close();
                        outStream = null;
                    }
                    if (null != bin) {
                        bin.close();
                        bin = null;
                    }
                    if (null != in) {
                        in.close();
                        in = null;
                    }
                } catch (IOException e) {
                    log.error("关闭文件流失败", e);
                    throw new RuntimeException(e.getMessage(), e);
                }
            }
        }
    }

    @Override
    public ResponseEntity<byte[]> downFileByResponseEntity(String sessionId, DownFileVO downFileVO, HttpServletResponse response) {
        Assert.notNull(downFileVO.getFileId(), "文件id不能为空!");
        if (downFileVO.getIsPack().equals(StateConstants.COMMON_ONE)) {
            //将文件封装到压缩包中
            //将文件封装到临时压缩包中
            String zipPath = fileDownTemp + System.currentTimeMillis() + ".zip";
            InputStream zipInputStream = getFileZipInputStream(downFileVO.getFileId(), zipPath);
            byte[] zipBytes;
            try {
                zipBytes = FileUtils.read(zipInputStream);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            // 设置响应头，指定文件类型和下载的文件名
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/zip"));
            headers.setContentDispositionFormData("attachment", "D:\\" + UUID.fastUUID());
            // 返回响应实体
            return new ResponseEntity<byte[]>(zipBytes, headers, HttpStatus.OK);
        }
        //单个文件形式下载
        Assert.isTrue(CollectionUtils.isEmpty(downFileVO.getFileId()) || downFileVO.getFileId().size() != StateConstants.COMMON_ONE, "传参有误");
        StFile stFile = stFileMapper.selectOne(new QueryWrapper<StFile>().eq("id", downFileVO.getFileId().get(StateConstants.ZERO)));
        Assert.notNull(stFile, "参数错误");
        // 将输入流转换为字节数组
        InputStream inputStream = getDownInputStream(stFile);
        byte[] fileBytes;
        try {
            fileBytes = FileUtils.read(inputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 设置响应头，指定文件类型和下载的文件名
        HttpHeaders headers = new HttpHeaders();
        // 根据文件扩展名获取对应的 MIME 类型
        String contentType = getContentTypeByExtension(stFile.getExt());
        headers.setContentType(MediaType.parseMediaType(contentType));
        headers.setContentDispositionFormData("attachment", "D:\\" + stFile.getOriginalFilename());
        try {
            if (ObjectUtil.isNotEmpty(inputStream)) {
                inputStream.close();
            }
        } catch (IOException e) {
            log.error("异常描述", e);
            throw new RuntimeException(e.getMessage(), e);
        }
        // 返回响应实体
        return new ResponseEntity<byte[]>(fileBytes, headers, HttpStatus.OK);
    }

    @Override
    public String getFileUrl(Long fileId) {
        Assert.isNull(fileId, "文件id不能为空");
        StFile stFile = stFileMapper.selectById(fileId);
        if (!ObjectUtil.isNull(stFile)) {
            return stFile.getUrl();
        }
        return null;
    }

    public void deleteFile(Long fileId) {
        Assert.isNull(fileId, "参数错误:文件id不能为空");
        //查询文件信息
        StFile stFile = stFileMapper.selectById(fileId);
        Assert.isNull(stFile, "参数错误:文件不存在");
        //查询设配信息
        StEquipment stEquipment = stEquipmentMapper.selectById(stFile.getEquipmentId());
        Assert.isNull(stEquipment, "参数错误:设备信息不存在");
        //获取对应的存储平台
        FileStorage fileStorage = fileStorageService.getFileStorage(String.valueOf(stEquipment.getId()));
        fileStorage.delete(stFile.getObjectKey());
    }



    /**
     * 资源懒加载
     *
     * @param request     请求头
     * @param response    响应头
     * @param stFile      文件对象
     * @param inputStream 输入流
     * @param ext         文件后缀
     * @throws IOException 异常
     */
    private void loadVideosAudisoPaf(HttpServletRequest request, HttpServletResponse response, StFile stFile, InputStream inputStream, String ext) throws IOException {
        log.info("视频或音频分段获取资源");
        //视频
        //通过url获取的InputStream  inputStream.available()并不总是返回文件的实际长度。 所以需要获取其实际长度 inputStream.available()返回int类型 文件超出2147483647大小会有问题
        long fileLen = inputStream.available();
        if (log.isInfoEnabled()) {
            log.info("文件大小fileLen:{}", fileLen);
        }
        String range = request.getHeader("Range");
        response.setHeader("Accept-Ranges", "bytes");
        ServletOutputStream out = response.getOutputStream();
        if (range == null) {
            range = "bytes=0-";
        }
        long start = Long.parseLong(range.substring(range.indexOf("=") + 1, range.indexOf("-")));
        long count = fileLen - start;
        long end = 0;
        if (range.endsWith(SPLIT)) {
            end = fileLen - 1;
        } else {
            end = Long.parseLong(range.substring(range.indexOf("-") + 1));
        }
        String contentRange = "bytes " + String.valueOf(start) + "-" + end + "/" + String.valueOf(fileLen);
        response.setStatus(206);
        response.setContentType("application/octet-stream");
        response.setHeader("Content-Range", contentRange);

        byte[] buffer = new byte[1024 * 10];
        int length = 0;
        long skip = inputStream.skip(start);

        while ((length = inputStream.read(buffer)) != -1) {
            out.write(buffer, 0, length);
        }

        inputStream.close();
        inputStream = null;

        out.close();
        out = null;
    }


    /**
     * 加载pdf
     *
     * @param response 响应头
     * @param request  请求头
     * @param filePath pdf文件路径
     * @throws FileNotFoundException 异常
     */
    private void loadPdf(HttpServletResponse response, HttpServletRequest request, String filePath) throws FileNotFoundException {
        // 以下为pdf分片的代码
        try (InputStream is = new FileInputStream(filePath);
             BufferedInputStream bis = new BufferedInputStream(is);
             OutputStream os = response.getOutputStream();
             BufferedOutputStream bos = new BufferedOutputStream(os)) {

            // 下载的字节范围
            int startByte;
            int endByte;
            int totalByte;
            // 根据HTTP请求头的Range字段判断是否为断点续传
            if (request == null || request.getHeader(RANGE) == null) {
                // 如果是首次请求，返回全部字节范围 bytes 0-7285040/7285041
                totalByte = is.available();
                startByte = 0;
                endByte = totalByte - 1;
                // 跳过输入流中指定的起始位置
                response.setStatus(HttpServletResponse.SC_OK);
            } else {
                // 断点续传逻辑
                String[] range = request.getHeader(RANGE).replaceAll("[^0-9\\-]", "").split("-");
                // 文件总大小
                totalByte = is.available();
                // 下载起始位置
                startByte = Integer.parseInt(range[0]);
                // 下载结束位置
                endByte = range.length > 1 ? Integer.parseInt(range[1]) : totalByte - 1;

                // 跳过输入流中指定的起始位置
                long skip = bis.skip(startByte);

                // 表示服务器成功处理了部分 GET 请求，返回了客户端请求的部分数据。
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            }
            // 表明服务器支持分片加载
            response.setHeader("Accept-Ranges", "bytes");
            // Content-Range: bytes 0-65535/408244，表明此次返回的文件范围
            response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + totalByte);
            // 告知浏览器这是一个字节流，浏览器处理字节流的默认方式就是下载
            response.setContentType("application/octet-stream");
            // 表明该文件的所有字节大小
            response.setContentLength(endByte - startByte + 1);
            // 需要设置此属性，否则浏览器默认不会读取到响应头中的Accept-Ranges属性，
            // 因此会认为服务器端不支持分片，所以会直接全文下载
            response.setHeader("Access-Control-Expose-Headers", "Accept-Ranges,Content-Range");
            // 第一次请求直接刷新输出流，返回响应
            int bytesRead;
            int length = endByte - startByte + 1;
            byte[] buffer = new byte[1024 * 10];
            while ((bytesRead = bis.read(buffer, 0, Math.min(buffer.length, length))) != -1 && length > 0) {
                bos.write(buffer, 0, bytesRead);
                length -= bytesRead;
            }
            response.flushBuffer();
            bos.close();
            bis.close();
        } catch (IOException e) {
            log.error("异常描述", e);
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    /**
     * 将文件封装到压缩包中得到压缩文件的文件流
     *
     * @param fileList 下载对象
     * @param zipPath  生成的压缩文件临时路径
     * @return Result
     */
    private InputStream getFileZipInputStream(List<Long> fileList, String zipPath) {
        List<StFile> stStFileList = stFileMapper.selectListByIdSourt(fileList);
        Assert.notNull(stStFileList, "文件不存在");
        InputStream inputStream = null;
        // 使用ZipOutputStream将字节数组输出流封装为压缩流，这样可以将文件逐个添加到压缩包中
        // 判断目录存储不存在 不存在则创建
        //文件下载临时路径
        String path = fileDownTemp + System.currentTimeMillis();
        try {
            // 创建一个计数器
            CountDownLatch latch = new CountDownLatch(stStFileList.size());
            for (StFile stFile : stStFileList) {
                inputStream = null;
                if (inputStream == null) {
                    log.info("直接获取流");
                    inputStream = getFileInputStream(String.valueOf(stFile.getEquipmentId()), stFile.getObjectKey(), stFile.getIsEncrypt(), stFile.getEncryptKey(), stFile.getEncryptIndex());
                }
                //异步下载文件
                asyncDownloadFileById(inputStream, path, latch, stFile);
            }
            try {
                latch.await();
                //所有线程都执行完毕，进行打包
                //打包
                ZipUtils.apacheZip(path, zipPath);
                //删除文件夹
                org.apache.commons.io.FileUtils.deleteDirectory(new File(path));
                // 将压缩后的字节数组zipBytes赋值为outputStream的内容。
                try {
                    return new FileInputStream(zipPath);
                } catch (FileNotFoundException e) {
                    if (log.isErrorEnabled()) {
                        log.error("压缩文件不存在");
                    }
                }
            } catch (Exception e) {
                log.error("异常描述", e);
                throw new MyException("打压缩包出错!");
            }
        } finally {
            try {
                log.info("正在关闭文件流");
                if (null != inputStream) {
                    inputStream.close();
                    inputStream = null;
                }
            } catch (IOException e) {
                log.error("关闭文件流失败,{}", e);
                throw new RuntimeException(e.getMessage(), e);
            }
        }
        return null;
    }

    /**
     * 从存储设备中获取文件流并解密
     *
     * @param equipmentId  设备id
     * @param objectKey    key
     * @param isEncrypt    是否加密
     * @param encryptKey   加密key
     * @param encryptIndex 加密标识
     * @return Result
     */
    private InputStream getFileInputStream(String equipmentId, String objectKey, Integer isEncrypt, String encryptKey, String encryptIndex) {
        //获取对应的存储平台
        FileStorage fileStorage = fileStorageService.getFileStorage(equipmentId);
        //从存储设备中获取文件流
        InputStream inputStream = fileStorage.getFileStream(objectKey);
        if (ObjectUtil.isNull(inputStream)) {
            log.info("从存储设备中获取文件流为空");
        }
        //是否加密
        if (StateConstants.IS_ENCRYPT.equals(isEncrypt)) {
            //解密
            inputStream = FileEncryptUtils.decrypt(inputStream, encryptKey, encryptIndex);
            if (ObjectUtil.isNull(inputStream)) {
                log.info("解密出的件流为空");
            }
        }
        return inputStream;
    }


    /**
     * 异步下载文件
     *
     * @param inputStream 输入流
     * @param path        地址
     * @param latch       CountDownLatch
     * @param stFile      文件对象
     */
    private void asyncDownloadFileById(InputStream inputStream, String path, CountDownLatch latch, StFile stFile) {
        executor.execute(() -> {
            try {
                Path directory = new File(path).toPath();
                Files.createDirectories(directory);

                Path targetFile = directory.resolve(stFile.getOriginalFilename());
                AtomicInteger num = new AtomicInteger(1);

                // 判断文件是否已存在，如果存在则修改文件名
                while (Files.exists(targetFile)) {
                    String name = stFile.getOriginalFilename().replaceFirst("[.][^.]+$", "");
                    String newFileName = String.format("%s(%d).%s", name, num.getAndIncrement(), stFile.getExt());
                    targetFile = directory.resolve(newFileName);
                }

                // 下载并保存文件
                Files.copy(inputStream, targetFile, StandardCopyOption.REPLACE_EXISTING);
                latch.countDown();
            } catch (Exception e) {
                // 异常处理逻辑
                log.error("下载报错",e);
            } finally {
                try {
                    if (inputStream != null) {
                        inputStream.close();
                    }
                } catch (Exception e) {
                    // 异常处理逻辑
                    log.error("关闭流报错",e);
                }
            }
        });
    }

    /**
     * 获取要下载的文件字节数组
     *
     * @param stFile            文件对象
     * @return Result
     */
    private InputStream getDownInputStream(StFile stFile) {
        InputStream inputStream = null;
        try {
            log.info("直接获取存储设备中的文件流");
            inputStream = getFileInputStream(String.valueOf(stFile.getEquipmentId()), stFile.getObjectKey(), stFile.getIsEncrypt(), stFile.getEncryptKey(), stFile.getEncryptIndex());
        } catch (Exception e) {
            log.error("异常描述", e);
            throw new RuntimeException(e.getMessage(), e);
        }
        return inputStream;
    }

    /**
     * 得到文件原始名称
     * @param downFileVO downFileVO
     * @param stFile stFile
     * @return Result
     */
    public static String getOriginalFilename(DownFileVO downFileVO, StFile stFile) {
        String originalFilename = null;
        Map<String, String> fileIdNameMap = downFileVO.getFileIdNameMap();
        if (ObjectUtils.isEmpty(fileIdNameMap)) {
            originalFilename = stFile.getOriginalFilename();
        } else {
            String fileName = fileIdNameMap.get(String.valueOf(stFile.getId()));
            originalFilename = ObjectUtils.isEmpty(fileName) ? stFile.getOriginalFilename() : fileName;
        }
        return originalFilename;
    }

    /**
     * 获取文件类型
     * @param fileExtension fileExtension
     * @return Result
     */
    public static String getContentTypeByExtension(String fileExtension) {
        if (fileExtension == null) {
            return null;
        }
        String contentType;
        switch (fileExtension.toLowerCase()) {
            case "pdf":
                contentType = "application/pdf";
                break;
            case "txt":
                contentType = "text/plain";
                break;
            case "jpg":
            case "jpeg":
                contentType = "image/jpeg";
                break;
            case "png":
                contentType = "image/png";
                break;
            case "doc":
            case "docx":
                contentType = "application/vnd.ms-word";
                break;
            case "xls":
            case "xlsx":
                contentType = "application/vnd.ms-excel";
                break;
            // 添加更多文件扩展名和对应的 MIME 类型
            default:
                contentType = "application/octet-stream";
                break;
        }
        return contentType;
    }
}
